#include "planetary_system.h"

#include <QtGui\QGroupBox>
#include <QtGui\QGridLayout>
#include <QtGui\QAction>
#include <QtGui\QMenuBar>
#include <QtGui\QFileDialog>
#include <QtGui\QMessageBox>

#include "math_model.h"
#include "solvers.h"
#include "PSGL\psglvisualizer.h"
#include "PSGL\psglmodel.h"

PlanetarySystemWidget::PlanetarySystemWidget(QWidget *parent /* = NULL */)
  : QMainWindow(parent)  
  , solverDialog(NULL)
  , plotDialog(NULL)
  , graphicsOptionDialog(NULL)
  , planetSystemView(NULL)
{
  mathModel = new MathModel();

  QWidget* centralWidget = new QWidget(this);
  // OpenGl panel constructor
  drawingPanel = new PSGLScene(this);//new QGroupBox(QString("Drawing panel"), this);

  solveButton = new QPushButton(QString("Solve!"), this);
  connect(solveButton, SIGNAL(clicked()), this, SLOT(runSolverDialog()));

  animationScroller = new AnimationScroller(this);
  animationScroller->setEnabled(false);
  connect(animationScroller, SIGNAL(animationAtFrame(int)), drawingPanel, SLOT(changeFrame(int)));
  //connect(animationScroller->slider, SIGNAL(valueChanged(int)), drawingPanel, SLOT(changeFrame(int))); 
  //connect(animationScroller, SIGNAL(animationAtFrame(int)), drawingPanel, SLOT(changeFrame(int))); 
  QGridLayout* pLayout = new QGridLayout(this);
  pLayout->addWidget(solveButton, 1, 7, 1, 2);
  pLayout->addWidget(drawingPanel, 2, 0, 1, 9);
  pLayout->addWidget(animationScroller, 3, 0, 1, 9);
  centralWidget->setLayout(pLayout);

  setCentralWidget(centralWidget);

  openAct = new QAction(tr("&Open"), this);
  openAct->setShortcuts(QKeySequence::Open);
  openAct->setStatusTip(tr("Open file"));
  connect(openAct, SIGNAL(triggered()), this, SLOT(fileOpen()));

  exitAct = new QAction(tr("&Exit"), this);
  exitAct->setShortcuts(QKeySequence::Quit);
  exitAct->setStatusTip(tr("Quit program"));
  connect(exitAct, SIGNAL(triggered()), this, SLOT(fileExit()));

  fileMenu = menuBar()->addMenu(tr("&File"));
  fileMenu->addAction(openAct);
  fileMenu->addAction(exitAct);

  plotAct = new QAction(tr("&Plot"), this);
  plotAct->setStatusTip(tr("Draw emenrgy or momentum plots"));
  connect(plotAct, SIGNAL(triggered()), this, SLOT(analysisPlot()));

  analysisMenu = menuBar()->addMenu(tr("&Analysis"));
  analysisMenu->addAction(plotAct);

  grahpicOptions = new QAction(tr("&Graphics parameters"), this);
  grahpicOptions->setStatusTip(tr("Change parameters of graphics"));
  connect(grahpicOptions, SIGNAL(triggered()), this, SLOT(runGraphicOptionsDialog()));

  optionsMenu = menuBar()->addMenu(tr("&Options"));
  optionsMenu->addAction(grahpicOptions);

  if (!mathModel->solved())
     analysisMenu->setEnabled(false);
  
  planetList = new QAction(tr("&Planet list"), this);
  connect(planetList, SIGNAL(triggered()), this, SLOT(runPlanetListDialog()));
  
  systemMenu = menuBar()->addMenu(tr("&System"));
  systemMenu->addAction(planetList);
  systemMenu->setEnabled(false);

  setWindowTitle(QString("Planetary System"));
}

PlanetarySystemWidget::~PlanetarySystemWidget()
{
  if (mathModel)
    delete mathModel;
}

// SLOTS
void PlanetarySystemWidget::fileOpen()
{
  QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", tr("Files (*.txt)"));
  if (fileName.length() > 0)
  { 
    bool ok = mathModel->loadFromFile(fileName);
    if (!ok)
    {
      QMessageBox* errorMessageBox = new QMessageBox(QMessageBox::Critical,"Error", "Invalid file format!", QMessageBox::Close);
      errorMessageBox->show();
      setWindowTitle(QString("Planetary System"));
    }
    else
    {
      setWindowTitle(fileName + QString(" - Planetary System"));
      if (!mathModel->solved())
      {
        animationScroller->setEnabled(false);
        analysisMenu->setEnabled(false);
      }
      else
      {
        animationScroller->setEnabled(true);
        animationScroller->setScale(mathModel->planetSystem[0].path.size());
        analysisMenu->setEnabled(true);
      }
      animationScroller->toStart();
      PSGLVisualizer::visualizeModel(mathModel, drawingPanel);
      drawingPanel->defaultScene();
      if (mathModel->planetSystem.size() > 0)
      {
        systemMenu->setEnabled(true);
        if (planetSystemView == NULL)
        {
          planetSystemView = new PlanetSystemDialog(mathModel, this);
          connect(planetSystemView, SIGNAL(mathModelChanged()), this, SLOT(mathModelChaned()));
          connect(planetSystemView, SIGNAL(planetNameChanged()), this, SLOT(planetNameChanged()));
        }
        else
          planetSystemView->setMathModel(mathModel);
      }
    }
  }

}

void PlanetarySystemWidget::fileExit()
{
  close();
}

void PlanetarySystemWidget::analysisPlot()
{
  if (!plotDialog)
   plotDialog = new PlotDialog(mathModel, this);
  plotDialog->setModel(mathModel);
  plotDialog->showMaximized();
}

void PlanetarySystemWidget::runSolverDialog()
{
  if (!solverDialog)
  {
    solverDialog = new SolverDialog(this);
    connect(solverDialog, SIGNAL(startSolution(const SolutionParameters&)), this, SLOT(runSolver(const SolutionParameters&)));
  }
  solverDialog->show();
}

void PlanetarySystemWidget::runSolver(const SolutionParameters& solPar)
{
  switch (solPar.type)
  {
  case TEST_SOLVER:
    {
      TestSolver* testSolver = new TestSolver();
      mathModel->solve(testSolver, solPar.tStart, solPar.tEnd, solPar.tDelta);
      delete testSolver;
      break;
    }
  case EXPLICIT_EULER:
    {
      ExplicitEulerSolver* explicitEulerSolver = new ExplicitEulerSolver();
      mathModel->solve(explicitEulerSolver, solPar.tStart, solPar.tEnd, solPar.tDelta);
      delete explicitEulerSolver;
      break;
    }
  case RUNGE_KUTTA:
    {
      RungeKuttaSolver* rungeKuttaSolver = new RungeKuttaSolver();
      mathModel->solve(rungeKuttaSolver, solPar.tStart, solPar.tEnd, solPar.tDelta);
      delete rungeKuttaSolver;
      break;
    }
  }
  animationScroller->setEnabled(true);
  analysisMenu->setEnabled(true);
  PSGLVisualizer::visualizeModel(mathModel, drawingPanel);
  drawingPanel->defaultScene();

  if (mathModel->solved())
    animationScroller->setScale(mathModel->planetSystem[0].path.size());
}




void PlanetarySystemWidget::runGraphicOptionsDialog()
{
  if (!graphicsOptionDialog)
  {
    graphicsOptionDialog = new GraphicsOptionDialog(this);
    connect(graphicsOptionDialog, SIGNAL(changeAnimationSpeed(int)), animationScroller, SLOT(newAnimationSpeed(int)));
    connect(graphicsOptionDialog, SIGNAL(changeObjects(int)), drawingPanel, SLOT(drawPlanet(int)));
    connect(graphicsOptionDialog, SIGNAL(changeTrajectories(int)), drawingPanel, SLOT(drawTrajectory(int)));
    connect(graphicsOptionDialog, SIGNAL(changeCaptions(int)), drawingPanel, SLOT(drawCaption(int)));
  }
  graphicsOptionDialog->show();
}

void PlanetarySystemWidget::runPlanetListDialog()
{
  if (planetSystemView == NULL)
  {
    planetSystemView = new PlanetSystemDialog(mathModel, this);
    connect(planetSystemView, SIGNAL(mathModelChanged()), this, SLOT(mathModelChaned()));
    connect(planetSystemView, SIGNAL(planetNameChanged()), this, SLOT(planetNameChanged()));
  }
  planetSystemView->show();
}

void PlanetarySystemWidget::mathModelChaned()
{
  animationScroller->setEnabled(false);
  analysisMenu->setEnabled(false);
  animationScroller->animationStop();
  PSGLVisualizer::visualizeModel(mathModel, drawingPanel);
  drawingPanel->update();
}

void PlanetarySystemWidget::planetNameChanged()
{
  PSGLVisualizer::visualizeModel(mathModel, drawingPanel);
  drawingPanel->update();
}